/**
 * 
 */
package com.example.spring_cloud_zuul.filter;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;

/**
 * 在完成了服务路由之后，对外开放服务还需要一些安全措施来保护客户端只能访问它应该访问到的资源。<br>
 * 所以需要利用Zuul的过滤器来实现对外服务的安全控制。 <br>
 * 在服务网关中定义过滤器只需要继承ZuulFilter抽象类实现其定义的四个抽象函数就可对请求进行拦截与过滤。
 */
public class AccessFilter extends ZuulFilter {
	private static Logger log = LoggerFactory.getLogger(AccessFilter.class);

	/**
	 * 过滤器的具体逻辑。需要注意，这里通过ctx.setSendZuulResponse(false)令zuul过滤该请求，<br>
	 * 不对其进行路由，然后通过ctx.setResponseStatusCode(401)设置了其返回的错误码，<br>
	 * 当然也可以进一步优化返回，比如 ，通过ctx.setResponseBody(body)对返回body内容进行编辑等。
	 */
	@Override
	public Object run() {
		// 定义了一个Zuul过滤器，实现了在请求被路由之前检查请求中是否有accessToken参数，
		// 若有就进行路由，若没有就拒绝访问，返回401 Unauthorized错误。
		RequestContext ctx = RequestContext.getCurrentContext();
		HttpServletRequest request = ctx.getRequest();
		log.info("{} request to {}", request.getMethod(), request.getRequestURL().toString());
		Object accessToken = request.getParameter("accessToken");
		if (accessToken == null) {
			log.warn("access token is empty");
			ctx.setSendZuulResponse(false);
			ctx.setResponseStatusCode(401);
			return null;
		}
		log.info("access token [{}] ok", accessToken);
		return null;
	}

	/**
	 * 返回一个boolean类型来判断该过滤器是否要执行，所以通过此函数可实现过滤器的开关。<br>
	 * 直接返回true，所以该过滤器总是生效。
	 */
	@Override
	public boolean shouldFilter() {
		return true;
	}

	/**
	 * 通过int值来定义过滤器的执行顺序
	 */
	@Override
	public int filterOrder() {
		return 0;
	}

	/**
	 * 返回一个字符串代表过滤器的类型，在zuul中定义了四种不同生命周期的过滤器类型，具体如下： <br>
	 * pre：可以在请求被路由之前调用 <br>
	 * routing：在路由请求时候被调用 <br>
	 * post：在routing和error过滤器之后被调用 <br>
	 * error：处理请求时发生错误时被调用
	 */
	@Override
	public String filterType() {
		return "pre";
	}

}
